/*
 * Copyright 2025 coze-dev Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { inject, injectable } from 'inversify';
import { FlowNodeBaseType } from '@flowgram-adapter/free-layout-editor';
import {
  type WorkflowDocumentOptions,
  type WorkflowLineEntity,
  type WorkflowPortEntity,
} from '@flowgram-adapter/free-layout-editor';
import { StandardNodeType } from '@coze-workflow/base/types';

import {
  WorkflowLinesServiceProvider,
  type WorkflowLinesService,
} from '../services/workflow-line-service';

@injectable()
export class WorkflowDocumentCustomOptions implements WorkflowDocumentOptions {
  @inject(WorkflowLinesServiceProvider)
  linesServiceProvider: () => WorkflowLinesService;

  // copy form packages/workflow-sdk/core/src/workflow-document-container-module.ts
  cursors: {
    grab: 'url(""), auto';
    grabbing: 'url(""), auto';
  };

  /** Is there an error in the connection? */
  isErrorLine(
    fromPort?: WorkflowPortEntity,
    toPort?: WorkflowPortEntity,
  ): boolean {
    const linesService = this.linesServiceProvider();
    return linesService.isError(fromPort?.node?.id, toPort?.node?.id);
  }

  /** Are the lines vertical? */
  isVerticalLine(line: WorkflowLineEntity): boolean {
    return this.isSubCanvasLinkLine(line);
  }

  /** Does the line hide the arrow? */
  isHideArrowLine(line: WorkflowLineEntity): boolean {
    return this.isSubCanvasLinkLine(line);
  }

  /** Is the line disabled? */
  isDisabledLine(line: WorkflowLineEntity): boolean {
    return this.isSubCanvasLinkLine(line);
  }

  /** Can lines be deleted? */
  canDeleteLine(line: WorkflowLineEntity): boolean {
    if (
      line.from?.flowNodeType === StandardNodeType.Loop &&
      line.to?.flowNodeType === FlowNodeBaseType.SUB_CANVAS
    ) {
      return false;
    }
    if (
      line.from?.flowNodeType === StandardNodeType.Batch &&
      line.to?.flowNodeType === FlowNodeBaseType.SUB_CANVAS
    ) {
      return false;
    }
    return true;
  }

  /** Are the two ports allowed to connect? */
  // eslint-disable-next-line complexity -- TODO configuration move to node
  canAddLine(
    fromPort: WorkflowPortEntity,
    toPort: WorkflowPortEntity,
  ): boolean {
    // Cannot be the same node self-looping
    if (fromPort.node === toPort.node) {
      return false;
    }
    if (toPort.node.flowNodeType === StandardNodeType.Comment) {
      return false;
    }
    // Child canvas nodes connect to sub-nodes
    if (
      (fromPort.node.flowNodeType === FlowNodeBaseType.SUB_CANVAS &&
        fromPort.node === toPort.node.parent) ||
      (toPort.node.flowNodeType === FlowNodeBaseType.SUB_CANVAS &&
        toPort.node === fromPort.node.parent)
    ) {
      return true;
    }
    // Loop and loopFunction connections cannot be changed
    if (
      toPort.portID === 'loop-function-inline-input' ||
      fromPort.portID === 'loop-function-inline-output' ||
      fromPort.portID === 'loop-output-to-function'
    ) {
      return false;
    }
    if (
      toPort.portID === 'batch-function-inline-input' ||
      fromPort.portID === 'batch-function-inline-output' ||
      fromPort.portID === 'batch-output-to-function'
    ) {
      return false;
    }
    // Not in different containers
    if (fromPort.node.parent?.id !== toPort.node.parent?.id) {
      return false;
    }
    // Unable to connect to wrong port
    if (
      fromPort.node.flowNodeType === 'error' ||
      toPort.node.flowNodeType === 'error'
    ) {
      return false;
    }
    return true;
  }

  private isSubCanvasLinkLine(line: WorkflowLineEntity): boolean {
    if (
      line.fromPort.portID === 'loop-output-to-function' &&
      line.toPort?.portID === 'loop-function-input'
    ) {
      return true;
    }
    if (
      line.fromPort.portID === 'batch-output-to-function' &&
      line.toPort?.portID === 'batch-function-input'
    ) {
      return true;
    }
    return false;
  }

  allNodesDefaultExpanded = false;
}
